--[[
-- Author:      feilong
-- DateTime:    2020-10-10 17:19:33
-- Description: 
    1开启集群节点
    2集群节点列表的维护
    3与nodeserver保持心跳
--]]


local skynet = require "skynet"
local cluster = require "skynet.cluster"

local table_insert = table.insert
local table_remove = table.remove

local ClusterManager = class("ClusterManager")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function ClusterManager:ctor(message_dispatch)
	
	self.cluster_center = skynet.getenv("cluster_center")		
    self.server_name = skynet.getenv("server_name")

	self.cluster_list = {} --集群列表{server_name = "192.xxx.xxx.xxx:xxxx"}
    self.node_list = {} --服务器节点列表

    self.node_info = nil --server_config.node_info

	self:register()
end

function ClusterManager:register()
    self.message_dispatch = g.MsgDis()
	self.message_dispatch:register('cluster_update_nt', handler(self,self.cluseterUpdateNt))
end

--打开自己的端口
function ClusterManager:open()	
    local server_config = dofile(skynet.getenv("server_config"))
    self.node_info = server_config.node_info
    if not self.node_info.enable then 
        print("集群节点不可用！")
        return
    end
	self:addNode(self.node_info)
    --打开监听
	cluster.open(self.server_name)
    --向中心节点注册
    if self.server_name ~= self.cluster_center then 
        print("__serverRegister__self.server_name__", self.server_name)
        self:serverRegister()
    end
    --发心跳包
    skynet.fork(function ( ... )
        while true do
            skynet.sleep(500)
            self:keepLife()
        end
    end)
end

--更新集群
function ClusterManager:updateCluster(node_info)
    -- 重新加载集群配置
    local name = node_info.name
    local cluster_addr = node_info.cluster_ip ..":".. node_info.cluster_port
    self.cluster_list[name] = cluster_addr
    self:addNode(node_info)
end


--返回集群列表
function ClusterManager:getClusterList()
	return self.cluster_list
end

function ClusterManager:addNode(node_info)   
    -- 重新加载集群配置
    -- g.Log():debug(node_info)
    local name = node_info.name
    self.cluster_list[name] = node_info.cluster_ip ..":".. node_info.cluster_port    

    -- g.Log():debug(self.cluster_list)
    cluster.reload(self.cluster_list)
    self.node_list[name] = node_info
end

-- 向clusterServer注册
function ClusterManager:serverRegister()
    if not self.cluster_center then
        return 
    end
    g.Message():callNodeManager(self.cluster_center, "server_register_req", self.node_info) 
end

--保持心跳
function ClusterManager:keepLife()
    -- g.Log():debug("___________keepLife")
    if not self.cluster_center then
        return 
    end
    g.Message():callNodeManager(self.cluster_center, "cluster_heart_req", self.node_info) 
end


function ClusterManager:removeNode(node_name)   
    -- 重新加载集群配置
    self.cluster_list[node_name] = nil        
    self.node_list[node_name] = nil        
    cluster.reload(self.cluster_list)
end

--获取服务器信息
function ClusterManager:getNode(name)
    return self.node_list[name]
end

--获取服务器节点列表
function ClusterManager:getNodeList()
    return self.node_list
end

--获取指定类型的节点列表
function ClusterManager:getNodesByType(node_type)    
    local node_list = {}
    for _, v in pairs(self.node_list) do         
        if v.enable == true and v.type == node_type then 
            table_insert(node_list, v)
        end
    end    
    return node_list
end

--获取指定类型的节点(id大的优先)
function ClusterManager:getNodeByType(node_type)    
    local max_id = 0
    local node = nil
    for _, v in pairs(self.node_list) do        
        if v.type == node_type and v.id > max_id then 
            max_id = v.id
            node = v
        end
    end    
    return node
end

function ClusterManager:getNodeByTypeId(node_type, server_id)    
    local max_id = 0
    local node = nil
    for _, v in pairs(self.node_list) do        
        if v.type == node_type and v.id == server_id then 
            max_id = v.id
            node = v
        end
    end    
    return node
end

--获取指定类型的节点
function ClusterManager:getNodeByTypeUid(node_type, uid)    
    local max_id = 0
    local nodes = self:getNodesByType(node_type)
    if not uid then 
        uid = 1
    end
    local index = uid % #nodes + 1 

    return nodes[index]
end

--给集群节点广播
function ClusterManager:broadcast(msg_name, msg)
    for k, v in pairs(self.cluster_list) do 
        if k ~= self.server_name then 
            g.Message():sendNodeManager(k, msg_name, self.server_name, msg) 
        end
    end
end

--发送消息到网关
function ClusterManager:sendGate(session, msg_name, msg_data, ...)
    local server_id = session >> 31
    local node = self:getNodeByTypeId("gateserver", server_id)
    g.Message():sendNodeManager(node.name, "send_to_user", session, msg_name, msg_data, ...)    
end

---------------------------------------------------------
-- CMD
---------------------------------------------------------

--收到通知更新集群列表
function ClusterManager:cluseterUpdateNt(msg_data)
	g.Log():debug("_________cluseterUpdateNt______", msg_data)
    for k, v in pairs(msg_data) do 
        self:updateCluster(v)
    end
    if next(msg_data) then 
        cluster.reload(self.cluster_list)
    end

	return true
end


return ClusterManager